home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 August / Chip_2004-08_cd1.bin / zkuste / fototools / download / phoa / phoa-setup.exe / {app} / API / phMetadata.pas next >
Pascal/Delphi Source File  |  2003-09-16  |  75KB  |  1,153 lines

  1. //**********************************************************************************************************************
  2. //
  3. // Image Metadata parsing routines
  4. //
  5. // The whole code (c)2003 Dmitry Kann, except where otherwise explicitly noted. The EXIF format is a Japan Electronic
  6. //   Industry Development Association (JEIDA) standard, revised June 1998 as version 2.1, and is not covered by this
  7. //   copyright nor GPL 2 terms.
  8. //
  9. // Home sites:
  10. //   http://devtools.narod.ru/
  11. //   http://phoa.narod.ru/
  12. //
  13. // Based on info from http://www.ba.wakwak.com/~tsuruzoh/
  14. //
  15. // History:
  16. //   Sep 08, 2003
  17. //     The first open source release of the unit
  18. //
  19. //   Sep ??, 2003
  20. //     Added some tags. Many tags became documented thanks to JEIDA specifications
  21. //     Added support for non-regular tags: Unicode, raw binary, Version etc.
  22. //     The code officially became covered with GPL 2 License, either supplied along with this unit, or available at
  23. //       http://www.gnu.org/copyleft/gpl.html
  24. //     PLEASE NOTE:
  25. //       The GPL 2 License does not permit incorporating this code into proprietary programs. If you find the unit
  26. //       useful and wish to compile it within a non-opensource code, please contact me at devtools@narod.ru
  27. //
  28. // Disclaimer:
  29. //   The software included comes with ABSOLUTELY NO WARRANTY. You may use it only at your own risk.
  30. //
  31. //**********************************************************************************************************************
  32. unit phMetadata;
  33.  
  34. interface
  35. uses SysUtils, Windows, Classes;
  36.  
  37. type
  38.    // Pointer to Metadata Instance, a specific need in PhoA
  39.   PImageMetadata = ^TImageMetadata;
  40.  
  41.    // Image Metadata retrieval object
  42.   TImageMetadata = class(TObject)
  43.   private
  44.      // True if any call failed
  45.     FFailed: Boolean;
  46.      // True if any data were fetched from the stream
  47.     FDataFetched: Boolean;
  48.      // Prop storage
  49.     FStatusCode: Integer;
  50.     FEXIFData: TStrings;
  51.      // Loading metadata from the stream
  52.     procedure LoadFromStream(Stream: TStream);
  53.      // Reads a two-byte data from the stream. If bMotorola=True, then swaps the LSB and MSB to provide an
  54.      //   Intel-byte-ordered word
  55.     function  FetchWord(Stream: TStream; bMotorola: Boolean): Word;
  56.      // Reads a marker data size and returns or discards (skips) the marker data from the stream
  57.     function  FetchMarkerData(Stream: TStream; bSkip: Boolean): String;
  58.      // Parses EXIF marker data
  59.     procedure ParseEXIFMarkerData(const sData: String);
  60.      // Sets FStatusCode. Any code but IMS_OK causes FFailed to be set to True
  61.     procedure SetStatusCode(iCode: Integer);
  62.      // Processes an IFD at given offset. bMotorola denotes whether Motorola byte-order is used.
  63.      //   Returns offset to the next IFD, if there's any, else 0
  64.     function ProcessIFD(const sData: String; iOffset: Integer; bMotorola: Boolean): Integer;
  65.   public
  66.     constructor Create(const sFileName: String);
  67.     destructor Destroy; override;
  68.      // Props
  69.     property EXIFData: TStrings read FEXIFData;
  70.      // -- One of the IMS_xxx constants, see below. Can use metadata only if StatusCode = IMS_OK
  71.     property StatusCode: Integer read FStatusCode;
  72.   end;
  73.  
  74.    // An IFD entry
  75.   PIFDEntry = ^TIFDEntry;
  76.   TIFDEntry = packed record
  77.     wTag:     Word;    // Tag ID
  78.     wFmt:     Word;    // Format (datatype) code
  79.     iCompCnt: Integer; // Component count
  80.     iData:    Integer; // Data or offset to data (if data length>4)
  81.   end;
  82.  
  83.    // The type of EXIF tag value
  84.   TEXIFTagValueType = (
  85.     xtvtRegular,     // Regular value: numbers are numbers, characters are characters etc.
  86.     xtvtUserComment, // Used for UserComment ($9286): first 8 bytes specify the charset, the next are character codes, whether one- or two-byte (depending on charset)
  87.     xtvtCharVersion, // Data are character codes, each char is separated with a period so they're version number
  88.     xtvtUnicode,     // Data are double-byte Unicode chars
  89.     xtvtBinary);     // Data are raw binary bytes
  90.  
  91.    // An EXIF tag
  92.   PEXIFTag = ^TEXIFTag; 
  93.   TEXIFTag = record
  94.     iTag:   Integer;           // Image's EXIF tag ID
  95.     VType:  TEXIFTagValueType; // Value type
  96.     sName:  AnsiString;        // Tag name
  97.     sVList: AnsiString;        // Value list in the format: 'value1=name1:value2=name2:...'
  98.     sDesc:  AnsiString;        // Tag description
  99.   end;
  100.  
  101. const
  102.    // Metadata discrepancies/errors
  103.   IMS_OK                       = 0000; // Metadata successfully parsed
  104.   IMS_CannotOpenFile           = 0001; // Unable to open file (file doesn't exist, access denied etc)
  105.   IMS_ReadFailure              = 0002; // Unable to read from file (EOF encountered, media error, access denied etc)
  106.   IMS_NotAJPEGFile             = 0010; // The file doesn't appear to be a JPEG file
  107.   IMS_NoMetadata               = 0011; // No metadata encountered in the file
  108.   IMS_InvalidEXIFHeader        = 0100; // EXIF header doesn't match
  109.   IMS_InvalidTIFFHeader        = 0101; // TIFF header (inside EXIF header) invalid or missing
  110.  
  111.   IMS_Unknown                  = 9999; // Unknown or internal error (possibly unhandled exception)
  112.  
  113.    // IFD Entry's data type
  114.   iedUByte                     = 0001;
  115.   iedAscii                     = 0002;
  116.   iedUShort                    = 0003;
  117.   iedULong                     = 0004;
  118.   iedURational                 = 0005;
  119.   iedSByte                     = 0006;
  120.   iedUndef                     = 0007;
  121.   iedSShort                    = 0008;
  122.   iedSLong                     = 0009;
  123.   iedSRational                 = 0010;
  124.   iedSingleFloat               = 0011;
  125.   iedDoubleFloat               = 0012;
  126.  
  127.    // IFD Entries' sizes
  128.   aIFDEntSize: Array[1..12] of Integer = (1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8);
  129.  
  130.    // JPEG Markers
  131.   JM_SOF0                      = $FFC0; // Start Of Frame N, N indicates compression process
  132.   JM_SOF1                      = $FFC1;
  133.   JM_SOF2                      = $FFC2;
  134.   JM_SOF3                      = $FFC3;
  135.   JM_DHT                       = $FFC4; // Define Huffman Table
  136.   JM_SOF5                      = $FFC5;
  137.   JM_SOF6                      = $FFC6;
  138.   JM_SOF7                      = $FFC7;
  139.   JM_SOF9                      = $FFC9;
  140.   JM_SOF10                     = $FFCA;
  141.   JM_SOF11                     = $FFCB;
  142.   JM_SOF13                     = $FFCD;
  143.   JM_DAC                       = $FFCC; // Define arithmetic coding conditioning
  144.   JM_SOF14                     = $FFCE;
  145.   JM_SOF15                     = $FFCF;
  146.   JM_SOI                       = $FFD8; // Start Of Image (beginning of datastream)
  147.   JM_EOI                       = $FFD9; // End Of Image (end of datastream)
  148.   JM_SOS                       = $FFDA; // Start Of Scan (begins compressed data)
  149.   JM_DQT                       = $FFDB; // Define Quantization Table
  150.   JM_DNL                       = $FFDC; // Define Number of Lines
  151.   JM_DRI                       = $FFDD; // Restart Interoperability Definition
  152.   JM_DHP                       = $FFDE; // Define Hierarchical Progression
  153.   JM_EXP                       = $FFDF; // Expand reference component
  154.   JM_JFIF                      = $FFE0; // JFIF marker
  155.   JM_EXIF                      = $FFE1; // EXIF marker
  156.   JM_EXIFEXT                   = $FFE2; // EXIF extended marker
  157.   JM_IPTC                      = $FFED; // IPTC (Photoshop datastream)
  158.   JM_APP14                     = $FFEE; // Photoshop data: App14
  159.   JM_COM                       = $FFFE; // Comment
  160.  
  161.    // EXIF section header
  162.   SEXIFHeader                  = 'Exif'#00#00;
  163.   STIFFIntelHeader             = 'II'#$2A#00;
  164.   STIFFMotorolaHeader          = 'MM'#00#$2A;
  165.  
  166.    // EXIF Tags
  167.   EXIF_TAG_SUBIFD              = $8769;
  168.   EXIF_TAG_INTEROPIFD          = $a005;
  169.  
  170.   EXIF_TAG_DATETIME            = $0132;
  171.   EXIF_TAG_DATETIME_ORIGINAL   = $9003;
  172.   EXIF_TAG_DATETIME_DIGITIZED  = $9004;
  173.  
  174.    // Some tags are taken from http://lxr.php.net/source/php4/ext/EXIF/EXIF.c, other from
  175.    //   http://www.ba.wakwak.com/~tsuruzoh/, and some from MSDN,
  176.    //   http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus 
  177.   aEXIFTags: Array[0..256] of TEXIFTag = (
  178.     (iTag: $0001; VType: xtvtRegular;     sName: 'Interoperability Index';               sVList: ''; sDesc: ''),
  179.     (iTag: $0002; VType: xtvtCharVersion; sName: 'Interoperability Version';             sVList: '';
  180.       sDesc: 'Records the interoperability version. "01.00" means version 1.00'),
  181.     (iTag: $000b; VType: xtvtRegular;     sName: 'ACD Comment';                          sVList: ''; sDesc: ''),
  182.     (iTag: $00fe; VType: xtvtRegular;     sName: 'New Subfile Type';                     sVList: '';
  183.       sDesc: 'Type of data in a subfile'),
  184.     (iTag: $00ff; VType: xtvtRegular;     sName: 'Subfile Type';                         sVList: '';
  185.       sDesc: 'Type of data in a subfile'),
  186.     (iTag: $0100; VType: xtvtRegular;     sName: 'Image Width';                          sVList: '';
  187.       sDesc: 'Original image width (number of pixels per row)'),
  188.     (iTag: $0101; VType: xtvtRegular;     sName: 'Image Height';                         sVList: '';
  189.       sDesc: 'Original image height (number of pixel rows)'),
  190.     (iTag: $0102; VType: xtvtRegular;     sName: 'Bits Per Sample';                      sVList: '';
  191.       sDesc:
  192.         'When image format is no compression, this value shows the number of bits per component for each pixel. '+
  193.         'Usually this value is "8,8,8"'),
  194.     (iTag: $0103; VType: xtvtRegular;     sName: 'Compression';                          sVList: '6=JPEG:3=Uncompressed:1=TIFF';
  195.       sDesc: 'Shows compression method used for the image data'),
  196.     (iTag: $0106; VType: xtvtRegular;     sName: 'Photometric Interpretation';           sVList: '1=Monochrome:2=RGB:6=YCbCr';
  197.       sDesc: 'Shows the color space of the image data components'),
  198.     (iTag: $0107; VType: xtvtRegular;     sName: 'ThreshHolding';                        sVList: '';
  199.       sDesc: 'Technique used to convert from gray pixels to black and white pixels'),
  200.     (iTag: $0108; VType: xtvtRegular;     sName: 'PropertyTagCellWidth';                 sVList: '';
  201.       sDesc: 'Width of the dithering or halftoning matrix'),
  202.     (iTag: $0109; VType: xtvtRegular;     sName: 'PropertyTagCellHeight';                sVList: '';
  203.       sDesc: 'Height of the dithering or halftoning matrix'),
  204.     (iTag: $010a; VType: xtvtRegular;     sName: 'FillOrder';                            sVList: '';
  205.       sDesc: 'Logical order of bits in a byte'),
  206.     (iTag: $010d; VType: xtvtRegular;     sName: 'Document Name';                        sVList: '';
  207.       sDesc: 'Specifies the name of the document from which the image was scanned'),
  208.     (iTag: $010e; VType: xtvtRegular;     sName: 'Image Description';                    sVList: '';
  209.       sDesc: 'Specifies the title of the image'),
  210.     (iTag: $010f; VType: xtvtRegular;     sName: 'Make';                                 sVList: '';
  211.       sDesc: 'Shows manufacturer of the equipment used to record the image'),
  212.     (iTag: $0110; VType: xtvtRegular;     sName: 'Model';                                sVList: '';
  213.       sDesc: 'Shows model name or model number of the equipment used to record the image'),
  214.     (iTag: $0111; VType: xtvtRegular;     sName: 'Strip Offsets';                        sVList: '';
  215.       sDesc:
  216.         'When image format is no compression, this value shows offset to image data. In some case image data is '+
  217.         'striped and this value is plural'),
  218.     (iTag: $0112; VType: xtvtRegular;     sName: 'Orientation';
  219.       sVList:
  220.         '1=Portrait (Top Left):2=Portrait (Top Right):3=Portrait (Bottom Right):4=Portrait (Bottom Left):'+
  221.         '5=Landscape (Left Top):6=Landscape (Right Top):7=Landscape (Right Bottom):8=Landscape (Left Bottom)';
  222.       sDesc:
  223.         'The orientation of the camera relative to the scene, when the image was captured. The relation is shown for '+
  224.         'the "0th row" of image to visual position'),
  225.     (iTag: $0115; VType: xtvtRegular;     sName: 'Samples Per Pixel';                    sVList: '';
  226.       sDesc:
  227.         'When image format is no compression, this value shows the number of components stored for each pixel. For '+
  228.         'color image this value is 3'),
  229.     (iTag: $0116; VType: xtvtRegular;     sName: 'Rows Per Strip';                       sVList: '';
  230.       sDesc:
  231.         'When image format is no compression and image has stored as strip, this value shows how many rows stored to '+
  232.         'each strip. If image has not striped, this value is the same as Image Height'),
  233.     (iTag: $0117; VType: xtvtRegular;     sName: 'Strip Byte Counts';                    sVList: '';
  234.       sDesc:
  235.         'When image format is no compression and stored as strip, this value shows how many bytes used for each strip '+
  236.         'and this value is plural. If image has not striped, this value is single and means whole data size of the '+
  237.         'image'),
  238.     (iTag: $0118; VType: xtvtRegular;     sName: 'Min Sample Value';                     sVList: '';
  239.       sDesc: 'For each color component, the minimum value assigned to that component'),
  240.     (iTag: $0119; VType: xtvtRegular;     sName: 'Max Sample Value';                     sVList: '';
  241.       sDesc: 'For each color component, the maximum value assigned to that component'),
  242.     (iTag: $011a; VType: xtvtRegular;     sName: 'X-Resolution';                         sVList: '';
  243.       sDesc:
  244.         'Display/Print resolution of image in the image width (x) direction. Default value is 1/72 inch, but it has '+
  245.         'no meaning because personal computer doesn''t use this value to display/print out'),
  246.     (iTag: $011b; VType: xtvtRegular;     sName: 'Y-Resolution';                         sVList: '';
  247.       sDesc:
  248.         'Display/Print resolution of image in the image height (y) direction. Default value is 1/72 inch, but it has '+
  249.         'no meaning because personal computer doesn''t use this value to display/print out'),
  250.     (iTag: $011c; VType: xtvtRegular;     sName: 'Planar Configuration';                 sVList: '';
  251.       sDesc:
  252.         'When image format is no compression YCbCr, this value shows byte aligns of YCbCr data. If value is 1, '+
  253.         'Y/Cb/Cr value is chunky format, contiguous for each subsampling pixel. If value is 2, Y/Cb/Cr value is '+
  254.         'separated and stored to Y plane/Cb plane/Cr plane format'),
  255.     (iTag: $011d; VType: xtvtRegular;     sName: 'Page Name';                            sVList: '';
  256.       sDesc: 'Specifies the name of the page from which the image was scanned'),
  257.     (iTag: $011e; VType: xtvtRegular;     sName: 'X-Position';                           sVList: '';
  258.       sDesc:
  259.         'Offset from the left side of the page to the left side of the image. The unit of measure is specified by '+
  260.         'Resolution Unit'),
  261.     (iTag: $011f; VType: xtvtRegular;     sName: 'Y-Position';                           sVList: '';
  262.       sDesc:
  263.         'Offset from the top edge of the page to the top edge of the image. The unit of measure is specified by '+
  264.         'Resolution Unit'),
  265.     (iTag: $0120; VType: xtvtRegular;     sName: 'Free Offsets';                         sVList: '';
  266.       sDesc: 'For each string of contiguous unused bytes, the byte offset of that string'),
  267.     (iTag: $0121; VType: xtvtRegular;     sName: 'Free Byte Counts';                     sVList: '';
  268.       sDesc: 'For each string of contiguous unused bytes, the number of bytes in that string'),
  269.     (iTag: $0122; VType: xtvtRegular;     sName: 'Gray Reponse Unit';
  270.       sVList: '1=1/10:2=1/100:3=1/1000:4=1/10000:5=1/100000:6=1/1000000';
  271.       sDesc: 'Precision of the number specified by Gray Response Curve'),
  272.     (iTag: $0123; VType: xtvtRegular;     sName: 'Gray Reponse Curve';                   sVList: '';
  273.       sDesc: 'For each possible pixel value in a grayscale image, the optical density of that pixel value'),
  274.     (iTag: $0124; VType: xtvtRegular;     sName: 'T4 Options';                           sVList: '';
  275.       sDesc: 'Set of flags that relate to T4 encoding'),
  276.     (iTag: $0125; VType: xtvtRegular;     sName: 'T6 Options';                           sVList: '';
  277.       sDesc: 'Set of flags that relate to T6 encoding'),
  278.     (iTag: $0128; VType: xtvtRegular;     sName: 'Resolution Unit';                      sVList: '1=None Specified:2=Inch:3=Centimeter';
  279.       sDesc: 'Unit of measure for the horizontal resolution and the vertical resolution'),
  280.     (iTag: $0129; VType: xtvtRegular;     sName: 'Page Number';                          sVList: '';
  281.       sDesc: 'Page number of the page from which the image was scanned'),
  282.     (iTag: $012d; VType: xtvtRegular;     sName: 'Transfer Function';                    sVList: '';
  283.       sDesc: 'Tables that specify transfer functions for the image'),
  284.     (iTag: $0131; VType: xtvtRegular;     sName: 'Software';                             sVList: '';
  285.       sDesc: 'Specifies the name and version of the software or firmware of the device used to generate the image'),
  286.     (iTag: $0132; VType: xtvtRegular;     sName: 'Date & Time';                          sVList: '';
  287.       sDesc:
  288.         'Date/Time of image was created or last modified. If clock wasn''t set or digicam doesn''t have clock, the '+
  289.         'field may be empty. Usually the same value as Original Date & Time'),
  290.     (iTag: $013b; VType: xtvtRegular;     sName: 'Artist';                               sVList: '';
  291.       sDesc: 'Specifies the name of the person who created the image'),
  292.     (iTag: $013c; VType: xtvtRegular;     sName: 'Host Computer';                        sVList: '';
  293.       sDesc: 'Specifies the computer and/or operating system used to create the image'),
  294.     (iTag: $013d; VType: xtvtRegular;     sName: 'Predictor';                            sVList: '';
  295.       sDesc: 'Type of prediction scheme that was applied to the image data before the encoding scheme was applied'),
  296.     (iTag: $013e; VType: xtvtRegular;     sName: 'White Point';                          sVList: '';
  297.       sDesc:
  298.         'Defines chromaticity of white point of the image. If the image uses CIE Standard Illumination D65 (known as '+
  299.         'international standard of "daylight"), the values are 3127/10000 & 3290/10000'),
  300.     (iTag: $013f; VType: xtvtRegular;     sName: 'Primary Chromaticities';               sVList: '';
  301.       sDesc:
  302.         'Defines chromaticity for each of the three primary colors in the image. If the image uses CCIR '+
  303.         'Recommendation 709 primaries, values are 640/1000, 330/1000, 300/1000, 600/1000, 150/1000, 0/1000'),
  304.     (iTag: $0140; VType: xtvtRegular;     sName: 'Color Map';                            sVList: '';
  305.       sDesc: 'Color palette (lookup table) for a palette-indexed image (consisting of 16-bit words)'),
  306.     (iTag: $0141; VType: xtvtRegular;     sName: 'Half Tone Hints';                      sVList: '';
  307.       sDesc: 'Information used by the halftone function'),
  308.     (iTag: $0142; VType: xtvtRegular;     sName: 'Tile Width';                           sVList: '';
  309.       sDesc: 'Number of pixel columns in each tile'),
  310.     (iTag: $0143; VType: xtvtRegular;     sName: 'Tile Length';                          sVList: '';
  311.       sDesc: 'Number of pixel rows in each tile'),
  312.     (iTag: $0144; VType: xtvtRegular;     sName: 'Tile Offsets';                         sVList: '';
  313.       sDesc: 'For each tile, the byte offset of that tile'),
  314.     (iTag: $0145; VType: xtvtRegular;     sName: 'Tile Byte Counts';                     sVList: '';
  315.       sDesc: 'For each tile, the number of bytes in that tile'),
  316.     (iTag: $014a; VType: xtvtRegular;     sName: 'SubIFDs';                              sVList: ''; sDesc: ''),
  317.     (iTag: $014c; VType: xtvtRegular;     sName: 'Ink Set';                              sVList: '';
  318.       sDesc: 'Set of inks used in a separated image'),
  319.     (iTag: $014d; VType: xtvtRegular;     sName: 'Ink Names';                            sVList: '';
  320.       sDesc:
  321.         'Sequence of concatenated, null-terminated, character strings that specify the names of the inks used in a '+
  322.         'separated image'),
  323.     (iTag: $014e; VType: xtvtRegular;     sName: 'Number Of Inks';                       sVList: '';
  324.       sDesc: 'Number of inks'),
  325.     (iTag: $0150; VType: xtvtRegular;     sName: 'Dot Range';                            sVList: '';
  326.       sDesc: 'Color component values that correspond to a 0 percent dot and a 100 percent dot'),
  327.     (iTag: $0151; VType: xtvtRegular;     sName: 'Target Printer';                       sVList: '';
  328.       sDesc: 'Describes the intended printing environment'),
  329.     (iTag: $0152; VType: xtvtRegular;     sName: 'Extra Sample';                         sVList: '';
  330.       sDesc: 'Number of extra color components. For example, one extra component might hold an alpha value'),
  331.     (iTag: $0153; VType: xtvtRegular;     sName: 'Sample Format';                        sVList: '';
  332.       sDesc: 'For each color component, the numerical format (unsigned, signed, floating point) of that component'),
  333.     (iTag: $0154; VType: xtvtRegular;     sName: 'SMin Sample Value';                    sVList: '';
  334.       sDesc: 'For each color component, the minimum value of that component'),
  335.     (iTag: $0155; VType: xtvtRegular;     sName: 'SMax Sample Value';                    sVList: '';
  336.       sDesc: 'For each color component, the maximum value of that component'),
  337.     (iTag: $0156; VType: xtvtRegular;     sName: 'Transfer Range';                       sVList: '';
  338.       sDesc: 'Table of values that extends the range of the transfer function'),
  339.     (iTag: $0157; VType: xtvtRegular;     sName: 'Clip Path';                            sVList: ''; sDesc: ''),
  340.     (iTag: $0158; VType: xtvtRegular;     sName: 'X-Clip Path Units';                    sVList: ''; sDesc: ''),
  341.     (iTag: $0159; VType: xtvtRegular;     sName: 'Y-Clip Path Units';                    sVList: ''; sDesc: ''),
  342.     (iTag: $015a; VType: xtvtRegular;     sName: 'Indexed';                              sVList: ''; sDesc: ''),
  343.     (iTag: $015b; VType: xtvtRegular;     sName: 'JPEG Tables';                          sVList: ''; sDesc: ''),
  344.     (iTag: $015f; VType: xtvtRegular;     sName: 'OPI Proxy';                            sVList: ''; sDesc: ''),
  345.     (iTag: $0200; VType: xtvtRegular;     sName: 'JPEG Proc';                            sVList: '';
  346.       sDesc: 'When image format is JPEG - the JPEG compression process'),
  347.     (iTag: $0201; VType: xtvtRegular;     sName: 'JPEG Interchange Format';              sVList: '';
  348.       sDesc: 'When image format is JPEG - offset to JPEG bitstream'),
  349.     (iTag: $0202; VType: xtvtRegular;     sName: 'JPEG Interchange Format Length';       sVList: '';
  350.       sDesc: 'When image format is JPEG - length, in bytes, of the JPEG bitstream'),
  351.     (iTag: $0203; VType: xtvtRegular;     sName: 'JPEG Restart Interval';                sVList: '';
  352.       sDesc: 'When image format is JPEG - length of the restart interval'),
  353.     (iTag: $0205; VType: xtvtRegular;     sName: 'JPEG Lossless Predictors';             sVList: '';
  354.       sDesc:
  355.         'When image format is JPEG - for each color component, a lossless predictor-selection value for that component'),
  356.     (iTag: $0206; VType: xtvtRegular;     sName: 'JPEG Point Transforms';                sVList: '';
  357.       sDesc: 'When image format is JPEG - for each color component, a point transformation value for that component'),
  358.     (iTag: $0207; VType: xtvtRegular;     sName: 'JPEG QTables';                         sVList: '';
  359.       sDesc:
  360.         'When image format is JPEG - for each color component, the offset to the quantization table for that component'),
  361.     (iTag: $0208; VType: xtvtRegular;     sName: 'JPEG DCTables';                        sVList: '';
  362.       sDesc:
  363.         'When image format is JPEG - for each color component, the offset to the DC Huffman table (or lossless '+
  364.         'Huffman table) for that component'),
  365.     (iTag: $0209; VType: xtvtRegular;     sName: 'JPEG ACTables';                        sVList: '';
  366.       sDesc:
  367.         'When image format is JPEG - for each color component, the offset to the AC Huffman table for that component'),
  368.     (iTag: $0211; VType: xtvtRegular;     sName: 'YCbCr Coefficients';                   sVList: '';
  369.       sDesc:
  370.         'When image format is YCbCr, this value shows a constant to translate it to RGB format. As usual values are '+
  371.         '0.299, 0.587, 0.114'),
  372.     (iTag: $0212; VType: xtvtRegular;     sName: 'YCbCr Subsampling';                    sVList: '';
  373.       sDesc:
  374.         'When image format is YCbCr and uses subsampling (cropping of chroma data, all digicams do that), shows how '+
  375.         'many chroma data subsampled. First value shows horizontal, next value shows vertical subsample rate'),
  376.     (iTag: $0213; VType: xtvtRegular;     sName: 'YCbCr Positioning';                    sVList: '1=Center pixel:2=Datum point';
  377.       sDesc:
  378.         'When image format is YCbCr and uses subsampling (cropping of chroma data, all digicams do that), defines the '+
  379.         'chroma sample point of subsampling pixel array'),
  380.     (iTag: $0214; VType: xtvtRegular;     sName: 'Reference Black&White';                sVList: '';
  381.       sDesc:
  382.         'Shows reference value of black point and white point. In case of YCbCr format, first 2 show black/white of '+
  383.         'Y, next 2 are Cb, last 2 are Cr. In case of RGB format, first 2 show black/white of R, next 2 are G, last 2 '+
  384.         'are B'),
  385.     (iTag: $02bc; VType: xtvtRegular;     sName: 'Extensible Metadata Platform';         sVList: ''; sDesc: ''),
  386.     (iTag: $0301; VType: xtvtRegular;     sName: 'Gamma';                                sVList: '';
  387.       sDesc:
  388.         'Gamma value attached to the image. The gamma value is stored as a rational number (pair of long) with a '+
  389.         'numerator of 100000. For example, a gamma value of 2.2 is stored as the pair (100000, 45455)'),
  390.     (iTag: $0302; VType: xtvtRegular;     sName: 'ICC Profile Descriptor';               sVList: '';
  391.       sDesc: 'Identifies an ICC profile'),
  392.     (iTag: $0303; VType: xtvtRegular;     sName: 'SRGB Rendering Intent';
  393.       sVList: '0=Perceptual:1=Relative colorimetric:2=Saturation:3=Absolute colorimetric';
  394.       sDesc:
  395.         'How the image should be displayed as defined by the International Color Consortium (ICC):'#13+
  396.         ' ò Perceptual intent, which is suitable for photographs, gives good adaptation to the display device gamut '+
  397.         'at the expense of colorimetric accuracy.'#13+
  398.         ' ò Relative colorimetric intent is suitable for images (for example, logos) that require color appearance '+
  399.         'matching that is relative to the display device white point.'#13+
  400.         ' ò Saturation intent, which is suitable for charts and graphs, preserves saturation at the expense of hue '+
  401.         'and lightness.'#13+
  402.         ' ò Absolute colorimetric intent is suitable for proofs (previews of images destined for a different display '+
  403.         'device) that require preservation of absolute colorimetry.'),
  404.     (iTag: $0304; VType: xtvtRegular;     sName: 'Image Title';                          sVList: '';
  405.       sDesc: 'Specifies the title of the image'),
  406.     (iTag: $0320; VType: xtvtRegular;     sName: 'Image Title';                          sVList: '';
  407.       sDesc: 'Specifies the title of the image'),
  408.     (iTag: $1000; VType: xtvtRegular;     sName: 'Related Image File Format';            sVList: '';
  409.       sDesc: 'Records the file format of image file'),
  410.     (iTag: $1001; VType: xtvtRegular;     sName: 'Related Image Width';                  sVList: '';
  411.       sDesc: 'Shows image width'),
  412.     (iTag: $1002; VType: xtvtRegular;     sName: 'Related Image Height';                 sVList: '';
  413.       sDesc: 'Shows image heigth'),
  414.     (iTag: $5001; VType: xtvtRegular;     sName: 'Resolution X-Unit';                    sVList: '1=pixels per inch:2=pixels per centimeter';
  415.       sDesc: 'Units in which to display horizontal resolution'),
  416.     (iTag: $5002; VType: xtvtRegular;     sName: 'Resolution Y-Unit';                    sVList: '1=pixels per inch:2=pixels per centimeter';
  417.       sDesc: 'Units in which to display vertical resolution'),
  418.     (iTag: $5003; VType: xtvtRegular;     sName: 'Resolution X-Length Unit';
  419.       sVList: '1=inches:2=centimeters:3=points:4=picas:5=columns';
  420.       sDesc: 'Units in which to display the image width'),
  421.     (iTag: $5004; VType: xtvtRegular;     sName: 'Resolution Y-Length Unit';
  422.       sVList: '1=inches:2=centimeters:3=points:4=picas:5=columns';
  423.       sDesc: 'Units in which to display the image height'),
  424.     (iTag: $5005; VType: xtvtRegular;     sName: 'Print Flags';                          sVList: '';
  425.       sDesc: 'Sequence of one-byte Boolean values that specify printing options'),
  426.     (iTag: $5006; VType: xtvtRegular;     sName: 'Print Flags Version';                  sVList: ''; 
  427.       sDesc: 'Print flags version'),
  428.     (iTag: $5007; VType: xtvtRegular;     sName: 'Print Flags Crop';                     sVList: ''; 
  429.       sDesc: 'Print flags center crop marks'),
  430.     (iTag: $5008; VType: xtvtRegular;     sName: 'Print Flags Bleed Width';              sVList: ''; 
  431.       sDesc: 'Print flags bleed width'),
  432.     (iTag: $5009; VType: xtvtRegular;     sName: 'Print Flags Bleed Width Scale';        sVList: ''; 
  433.       sDesc: 'Print flags bleed width scale'),
  434.     (iTag: $500a; VType: xtvtRegular;     sName: 'Halftone LPI';                         sVList: ''; 
  435.       sDesc: 'Ink''s screen frequency, in lines per inch'),
  436.     (iTag: $500b; VType: xtvtRegular;     sName: 'Halftone LPI Unit';                    sVList: '1=lines per inch:2=lines per centimeter';
  437.       sDesc: 'Units for the screen frequency'),
  438.     (iTag: $500c; VType: xtvtRegular;     sName: 'Halftone Degree';                      sVList: ''; 
  439.       sDesc: 'Angle for screen'),
  440.     (iTag: $500d; VType: xtvtRegular;     sName: 'Halftone Shape';
  441.       sVList: '0=Round:1=Ellipse:2=Line:3=Square:4=Cross:6=Diamond';
  442.       sDesc: 'Shape of the halftone dots'),
  443.     (iTag: $500e; VType: xtvtRegular;     sName: 'Halftone Misc';                        sVList: '';
  444.       sDesc: 'Miscellaneous halftone information'),
  445.     (iTag: $500f; VType: xtvtRegular;     sName: 'Halftone Screen';                      sVList: '1=Use printer''s default screens:2=Other';
  446.       sDesc: 'Boolean value that specifies whether to use the printer''s default screens'),
  447.     (iTag: $5010; VType: xtvtRegular;     sName: 'JPEG Quality';                         sVList: '';
  448.       sDesc: 'Private tag used by the Adobe Photoshop format. Not for public use'),
  449.     (iTag: $5011; VType: xtvtRegular;     sName: 'Grid Size';                            sVList: '';
  450.       sDesc: 'Block of information about grids and guides'),
  451.     (iTag: $5012; VType: xtvtRegular;     sName: 'Thumbnail Format';                     sVList: '0=Raw RGB:1=JPEG';
  452.       sDesc: 'Format of the thumbnail image'),
  453.     (iTag: $5013; VType: xtvtRegular;     sName: 'Thumbnail Width';                      sVList: '';
  454.       sDesc: 'Width, in pixels, of the thumbnail image'),
  455.     (iTag: $5014; VType: xtvtRegular;     sName: 'Thumbnail Height';                     sVList: '';
  456.       sDesc: 'Height, in pixels, of the thumbnail image'),
  457.     (iTag: $5015; VType: xtvtRegular;     sName: 'Thumbnail ColorDepth';                 sVList: '';
  458.       sDesc: 'Bits per pixel (BPP) for the thumbnail image'),
  459.     (iTag: $5016; VType: xtvtRegular;     sName: 'Thumbnail Planes';                     sVList: '';
  460.       sDesc: 'Number of color planes for the thumbnail image'),
  461.     (iTag: $5017; VType: xtvtRegular;     sName: 'Thumbnail Raw Bytes';                  sVList: '';
  462.       sDesc: 'Byte offset between rows of pixel data'),
  463.     (iTag: $5018; VType: xtvtRegular;     sName: 'Thumbnail Size';                       sVList: '';
  464.       sDesc: 'Total size, in bytes, of the thumbnail image'),
  465.     (iTag: $5019; VType: xtvtRegular;     sName: 'Thumbnail CompressedSize';             sVList: '';
  466.       sDesc: 'Compressed size, in bytes, of the thumbnail image'),
  467.     (iTag: $501a; VType: xtvtRegular;     sName: 'Color Transfer Function';              sVList: '';
  468.       sDesc: 'Table of values that specify color transfer functions'),
  469.     (iTag: $501b; VType: xtvtRegular;     sName: 'Thumbnail Data';                       sVList: '';
  470.       sDesc: 'Raw thumbnail bits in JPEG or RGB format. Depends on Thumbnail Format'),
  471.     (iTag: $5020; VType: xtvtRegular;     sName: 'Thumbnail Image Width';                sVList: '';
  472.       sDesc: 'Number of pixels per row in the thumbnail image'),
  473.     (iTag: $5021; VType: xtvtRegular;     sName: 'Thumbnail Image Height';               sVList: '';
  474.       sDesc: 'Number of pixel rows in the thumbnail image'),
  475.     (iTag: $5022; VType: xtvtRegular;     sName: 'Thumbnail Bits Per Sample';            sVList: '';
  476.       sDesc: 'Number of bits per color component in the thumbnail image'),
  477.     (iTag: $5023; VType: xtvtRegular;     sName: 'Thumbnail Compression';                sVList: '';
  478.       sDesc: 'Compression method used for thumbnail image data'),
  479.     (iTag: $5024; VType: xtvtRegular;     sName: 'Thumbnail Photometric Interpretation'; sVList: '';
  480.       sDesc: 'How thumbnail pixel data will be interpreted'),
  481.     (iTag: $5025; VType: xtvtRegular;     sName: 'Thumbnail Image Description';          sVList: '';
  482.       sDesc: 'Specifies the title of the image'),
  483.     (iTag: $5026; VType: xtvtRegular;     sName: 'Thumbnail Equipment Make';             sVList: '';
  484.       sDesc: 'Specifies the manufacturer of the equipment used to record the thumbnail image'),
  485.     (iTag: $5027; VType: xtvtRegular;     sName: 'Thumbnail Equipment Model';            sVList: '';
  486.       sDesc: 'Specifies the model name or model number of the equipment used to record the thumbnail image'),
  487.     (iTag: $5028; VType: xtvtRegular;     sName: 'Thumbnail Strip Offsets';              sVList: '';
  488.       sDesc: 'For each strip in the thumbnail image, the byte offset of that strip'),
  489.     (iTag: $5029; VType: xtvtRegular;     sName: 'Thumbnail Orientation';
  490.       sVList:
  491.         '1=Portrait (Top Left):2=Portrait (Top Right):3=Portrait (Bottom Right):4=Portrait (Bottom Left):'+
  492.         '5=Landscape (Left Top):6=Landscape (Right Top):7=Landscape (Right Bottom):8=Landscape (Left Bottom)';
  493.       sDesc: 'Thumbnail image orientation'),
  494.     (iTag: $502a; VType: xtvtRegular;     sName: 'Thumbnail Samples Per Pixel';          sVList: '';
  495.       sDesc: 'Number of color components per pixel in the thumbnail image'),
  496.     (iTag: $502b; VType: xtvtRegular;     sName: 'Thumbnail Rows Per Strip';             sVList: '';
  497.       sDesc: 'Number of rows per strip in the thumbnail image'),
  498.     (iTag: $502c; VType: xtvtRegular;     sName: 'Thumbnail Strip Bytes Count';          sVList: '';
  499.       sDesc: 'For each thumbnail image strip, the total number of bytes in that strip'),
  500.     (iTag: $502d; VType: xtvtRegular;     sName: 'Thumbnail X-Resolution';               sVList: '';
  501.       sDesc: 'Thumbnail resolution in the width direction. The resolution unit is given in Thumbnail Resolution Unit'),
  502.     (iTag: $502e; VType: xtvtRegular;     sName: 'Thumbnail Y-Resolution';               sVList: '';
  503.       sDesc: 'Thumbnail resolution in the height direction. The resolution unit is given in Thumbnail Resolution Unit'),
  504.     (iTag: $502f; VType: xtvtRegular;     sName: 'Thumbnail Planar Configuration';       sVList: '';
  505.       sDesc: 'Whether pixel components in the thumbnail image are recorded in chunky or planar format'),
  506.     (iTag: $5030; VType: xtvtRegular;     sName: 'Thumbnail Resolution Unit';            sVList: '1=None Specified:2=Inch:3=Centimeter';
  507.       sDesc: 'Unit of measure for the horizontal resolution and the vertical resolution of the thumbnail image'),
  508.     (iTag: $5031; VType: xtvtRegular;     sName: 'Thumbnail Transfer Function';          sVList: ''; 
  509.       sDesc: 'Tables that specify transfer functions for the thumbnail image'),
  510.     (iTag: $5032; VType: xtvtRegular;     sName: 'Thumbnail Software Used';              sVList: '';
  511.       sDesc:
  512.         'Specifies the name and version of the software or firmware of the device used to generate the thumbnail image'),
  513.     (iTag: $5033; VType: xtvtRegular;     sName: 'Thumbnail Date & Time';                sVList: ''; 
  514.       sDesc: 'Date and time the thumbnail image was created or last modified'),
  515.     (iTag: $5034; VType: xtvtRegular;     sName: 'Thumbnail Artist';                     sVList: ''; 
  516.       sDesc: 'Specifies the name of the person who created the thumbnail image'),
  517.     (iTag: $5035; VType: xtvtRegular;     sName: 'Thumbnail White Point';                sVList: ''; 
  518.       sDesc: 'Chromaticity of the white point of the thumbnail image'),
  519.     (iTag: $5036; VType: xtvtRegular;     sName: 'Thumbnail Primary Chromatics';         sVList: ''; 
  520.       sDesc: 'For each of the three primary colors in the thumbnail image, the chromaticity of that color'),
  521.     (iTag: $5037; VType: xtvtRegular;     sName: 'Thumbnail YCbCr Coefficients';         sVList: '';
  522.       sDesc: 'Coefficients for transformation from RGB to YCbCr data for the thumbnail image'),
  523.     (iTag: $5038; VType: xtvtRegular;     sName: 'Thumbnail YCbCr Subsampling';          sVList: ''; 
  524.       sDesc: 'Sampling ratio of chrominance components in relation to the luminance component for the thumbnail image'),
  525.     (iTag: $5039; VType: xtvtRegular;     sName: 'Thumbnail YCbCr Positioning';          sVList: ''; 
  526.       sDesc: 'Position of chrominance components in relation to the luminance component for the thumbnail image'),
  527.     (iTag: $503a; VType: xtvtRegular;     sName: 'Thumbnail Ref Black&White';            sVList: ''; 
  528.       sDesc: 'Reference black point value and reference white point value for the thumbnail image'),
  529.     (iTag: $503b; VType: xtvtRegular;     sName: 'Thumbnail Copyright';                  sVList: ''; 
  530.       sDesc: 'Contains copyright information for the thumbnail image'),
  531.     (iTag: $5090; VType: xtvtRegular;     sName: 'Luminance Table';                      sVList: ''; 
  532.       sDesc:
  533.         'Luminance table. The luminance table and the chrominance table are used to control JPEG quality. '+
  534.         'A valid luminance or chrominance table has 64 entries. If an image has either a luminance table or a '+
  535.         'chrominance table, then it must have both tables'),
  536.     (iTag: $5091; VType: xtvtRegular;     sName: 'Chrominance Table';                    sVList: '';
  537.       sDesc:
  538.         'Chrominance table. The luminance table and the chrominance table are used to control JPEG quality. '+
  539.         'A valid luminance or chrominance table has 64 entries. If an image has either a luminance table or a '+
  540.         'chrominance table, then it must have both tables'),
  541.     (iTag: $5100; VType: xtvtRegular;     sName: 'Frame Delay';                          sVList: ''; 
  542.       sDesc: 'Time delay, in hundredths of a second, between two frames in an animated GIF image'),
  543.     (iTag: $5101; VType: xtvtRegular;     sName: 'Loop Count';                           sVList: '';
  544.       sDesc:
  545.         'For an animated GIF image, the number of times to display the animation. A value of 0 specifies that the '+
  546.         'animation should be displayed infinitely'),
  547.     (iTag: $5102; VType: xtvtRegular;     sName: 'Global Palette';                       sVList: '';
  548.       sDesc: 'Color palette for an indexed bitmap in a GIF image'),
  549.     (iTag: $5103; VType: xtvtRegular;     sName: 'Index Background';                     sVList: '';
  550.       sDesc: 'Index of the background color in the palette of a GIF image'),
  551.     (iTag: $5104; VType: xtvtRegular;     sName: 'IndexTransparent';                     sVList: '';
  552.       sDesc: 'Index of the transparent color in the palette of a GIF image'),
  553.     (iTag: $5110; VType: xtvtRegular;     sName: 'Pixel Unit';                           sVList: '0=Unknown';
  554.       sDesc: 'Unit for Pixel Per Unit (X) and Pixel Per Unit (Y)'),
  555.     (iTag: $5111; VType: xtvtRegular;     sName: 'Pixel Per Unit (X)';                   sVList: ''; 
  556.       sDesc: 'Pixels per unit in the x direction'),
  557.     (iTag: $5112; VType: xtvtRegular;     sName: 'Pixel Per Unit (Y)';                   sVList: '';
  558.       sDesc: 'Pixels per unit in the y direction'),
  559.     (iTag: $5113; VType: xtvtRegular;     sName: 'Palette Histogram';                    sVList: ''; 
  560.       sDesc: 'Palette histogram'),
  561.     (iTag: $800d; VType: xtvtRegular;     sName: 'Image ID';                             sVList: ''; sDesc: ''),
  562.     (iTag: $80e3; VType: xtvtRegular;     sName: 'Matteing';                             sVList: ''; sDesc: ''),
  563.     (iTag: $80e4; VType: xtvtRegular;     sName: 'Data Type';                            sVList: ''; sDesc: ''),
  564.     (iTag: $80e5; VType: xtvtRegular;     sName: 'Image Depth';                          sVList: ''; sDesc: ''),
  565.     (iTag: $80e6; VType: xtvtRegular;     sName: 'Tile Depth';                           sVList: ''; sDesc: ''),
  566.     (iTag: $828d; VType: xtvtRegular;     sName: 'CFA Repeat Pattern Dim';               sVList: ''; sDesc: ''),
  567.     (iTag: $828e; VType: xtvtRegular;     sName: 'CFA Pattern';                          sVList: ''; sDesc: ''),
  568.     (iTag: $828f; VType: xtvtRegular;     sName: 'Battery Level';                        sVList: ''; sDesc: ''),
  569.     (iTag: $8298; VType: xtvtRegular;     sName: 'Copyright';                            sVList: '';
  570.       sDesc: 'Contains copyright information'),
  571.     (iTag: $829a; VType: xtvtRegular;     sName: 'Exposure Time (sec)';                  sVList: '';
  572.       sDesc: 'Exposure time (reciprocal of shutter speed). Unit is second'),
  573.     (iTag: $829d; VType: xtvtRegular;     sName: 'F-Number';                             sVList: '';
  574.       sDesc: 'The actual F-Number (F-stop) of lens when the image was taken'),
  575.     (iTag: $83bb; VType: xtvtRegular;     sName: 'IPTC/NAA';                             sVList: ''; sDesc: ''),
  576.     (iTag: $84e3; VType: xtvtRegular;     sName: 'IT8 Raster Padding';                   sVList: ''; sDesc: ''),
  577.     (iTag: $84e5; VType: xtvtRegular;     sName: 'IT8 Color Table';                      sVList: ''; sDesc: ''),
  578.     (iTag: $8649; VType: xtvtRegular;     sName: 'Image Resource Information';           sVList: ''; sDesc: ''),
  579.     (iTag: $8769; VType: xtvtRegular;     sName: 'EXIF SubIFD Offset';                   sVList: '';
  580.       sDesc: 'File offset to EXIF SubIFD (Image File Directory)'),
  581.     (iTag: $8773; VType: xtvtRegular;     sName: 'ICC Profile';                          sVList: '';
  582.       sDesc: 'ICC profile embedded in the image'),
  583.     (iTag: $8822; VType: xtvtRegular;     sName: 'Exposure Program';
  584.       sVList:
  585.         '0=Unidentified:1=Manual:2=Normal:3=Aperture priority:4=Shutter priority:'+
  586.         '5=Creative (biased toward depth of field):6=Action (biased toward fast shutter speed):'+
  587.         '7=Portrait mode (for close-up photos with the background out of focus):'+
  588.         '8=Landscape mode (for landscape photos with the background in focus)';
  589.       sDesc: 'Exposure program that the camera used when image was taken'),
  590.     (iTag: $8824; VType: xtvtRegular;     sName: 'Spectral Sensitivity';                 sVList: '';
  591.       sDesc:
  592.         'Specifies the spectral sensitivity of each channel of the camera used. The string is compatible with the '+
  593.         'standard developed by the ASTM Technical Committee'),
  594.     (iTag: $8825; VType: xtvtRegular;     sName: 'GPS IFD Offset';                       sVList: '';
  595.       sDesc: 'Offset to a block of GPS property items'),
  596.     (iTag: $8827; VType: xtvtRegular;     sName: 'ISO Speed Ratings';                    sVList: '';
  597.       sDesc: 'ISO speed and ISO latitude of the camera or input device as specified in ISO 12232'),
  598.     (iTag: $8828; VType: xtvtRegular;     sName: 'OECF';                                 sVList: '';
  599.       sDesc:
  600.         'Optoelectronic conversion function (OECF) specified in ISO 14524. The OECF is the relationship between the '+
  601.         'camera optical input and the image values'),
  602.     (iTag: $8829; VType: xtvtRegular;     sName: 'Interlace';                            sVList: ''; sDesc: ''),
  603.     (iTag: $882a; VType: xtvtRegular;     sName: 'Time Zone Offset';                     sVList: ''; sDesc: ''),
  604.     (iTag: $882b; VType: xtvtRegular;     sName: 'Self Timer Mode';                      sVList: ''; sDesc: ''),
  605.     (iTag: $9000; VType: xtvtCharVersion; sName: 'EXIF Version';                         sVList: '';
  606.       sDesc:
  607.         'Version of the EXIF standard supported. Nonexistence of this field is taken to mean nonconformance to the '+
  608.         'standard. Conformance to the standard EXIF 2.1 is indicated by recording values 02.10'),
  609.     (iTag: $9003; VType: xtvtRegular;     sName: 'Original Date & Time';                 sVList: '';
  610.       sDesc:
  611.         'Date/Time of original image taken. This value should not be modified by user program. If clock wasn''t set '+
  612.         'or digicam doesn''t have clock, the field may be empty'),
  613.     (iTag: $9004; VType: xtvtRegular;     sName: 'Date & Time Digitized';                sVList: '';
  614.       sDesc:
  615.         'Date/Time of when the image was digitized. If clock wasn''t set or digicam doesn''t have clock, the field '+
  616.         'may be empty. Usually the same value as Original Date & Time'),
  617.     (iTag: $9101; VType: xtvtRegular;     sName: 'Components Configuration';             sVList: '';
  618.       sDesc:
  619.         'Information specific to compressed data. The channels of each component are arranged in order from the first '+
  620.         'component to the fourth. For uncompressed data, the data arrangement is given in the Photometric '+
  621.         'Interpretation tag. However, because Photometric Interpretation can only express the order of Y, Cb, and Cr, '+
  622.         'this tag is provided for cases when compressed data uses components other than Y, Cb, and Cr and to support '+
  623.         'other sequences. Most of case "0x04,0x05,0x06,0x00" is used for RGB-format and "0x01,0x02,0x03,0x00" for '+
  624.         'YCbCr-format. 0x00:does not exist, 0x01:Y, 0x02:Cb, 0x03:Cr, 0x04:Red, 0x05:Green, 0x06:Blue'),
  625.     (iTag: $9102; VType: xtvtRegular;     sName: 'Compressed Bits Per Pixel';            sVList: '';
  626.       sDesc: 'Information specific to compressed data. The average compression ratio of JPEG (rough estimate)'),
  627.     (iTag: $9201; VType: xtvtRegular;     sName: 'Shutter Speed Value';                  sVList: '';
  628.       sDesc:
  629.         'Shutter speed. The unit is the Additive System of Photographic Exposure (APEX) value. To convert this value '+
  630.         'to ordinary "Shutter Speed", calculate this value''s power of 2, then reciprocal. For example, if the value '+
  631.         'is 4, shutter speed is 1/16 second'),
  632.     (iTag: $9202; VType: xtvtRegular;     sName: 'Aperture Value';                       sVList: '';
  633.       sDesc:
  634.         'The actual aperture value of lens when the image was taken. The unit is the Additive System of Photographic '+
  635.         'Exposure (APEX) value. To convert this value to ordinary F-Number (F-Stop), calculate this value''s power of '+
  636.         'root 2 (=1.4142). For example, if the value is 5, F-Number is 1.4142^5 = F5.6'),
  637.     (iTag: $9203; VType: xtvtRegular;     sName: 'Brightness Value';                     sVList: '';
  638.       sDesc:
  639.         'Brightness of taken subject. The unit is the Additive System of Photographic Exposure (APEX) value. To '+
  640.         'calculate Exposure (Ev) from Brigtness Value (Bv), you must add Sensitivity Value (Sv). Ev=Bv+Sv; '+
  641.         'Sv=log2(ISOSpeedRating/3.125); ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32'),
  642.     (iTag: $9204; VType: xtvtRegular;     sName: 'Exposure Bias Value';                  sVList: '';
  643.       sDesc:
  644.         'Exposure bias (compensation) value of taking picture. The unit is the Additive System of Photographic '+
  645.         'Exposure (APEX) value. Ordinarily it is given in the range -99.99 to 99.99'),
  646.     (iTag: $9205; VType: xtvtRegular;     sName: 'Max Aperture Value';                   sVList: '';
  647.       sDesc:
  648.         'Maximum aperture value of lens (smallest F-number of the lens). You can convert to F-Number by calculating '+
  649.         'power of root 2 (same as Aperture Value)'),
  650.     (iTag: $9206; VType: xtvtRegular;     sName: 'Subject Distance (m)';                 sVList: '';
  651.       sDesc: 'Distance to focus point, unit is meter'),
  652.     (iTag: $9207; VType: xtvtRegular;     sName: 'Metering Mode';
  653.       sVList: '0=Unknown:1=Average:2=Center weighted average:3=Spot:4=Multi-spot:5=Multi-segment:6=Partial:255=Other';
  654.       sDesc: 'Exposure metering method'),
  655.     (iTag: $9208; VType: xtvtRegular;     sName: 'Light Source';
  656.       sVList:
  657.         '0=Unidentified:1=Daylight:2=Fluorescent:3=Tungsten:10=Flash:17=Standard light A:18=Standard light B:'+
  658.         '19=Standard light C:20=D55:21=D65:22=D75:255=Other';
  659.       sDesc: 'Light source; actually this means white balance setting'),
  660.     (iTag: $9209; VType: xtvtRegular;     sName: 'Flash';
  661.       sVList:
  662.         '0=Flash didn''t fire:1=Flash fired:5=Flash fired, strobe return light wasn''t detected:'+
  663.         '7=Flash fired, strobe return light detected';
  664.       sDesc: 'Flash usage while taking the picture'),
  665.     (iTag: $920a; VType: xtvtRegular;     sName: 'Focal Length (mm)';                    sVList: '';
  666.       sDesc:
  667.         'Actual focal length of lens used to take image. Unit is millimeter. Conversion is not made to the focal '+
  668.         'length of a 35 millimeter film camera'),
  669.     (iTag: $920b; VType: xtvtRegular;     sName: 'Flash Energy';                         sVList: ''; sDesc: ''),
  670.     (iTag: $920c; VType: xtvtRegular;     sName: 'Spatial Frequency Response';           sVList: ''; sDesc: ''),
  671.     (iTag: $920d; VType: xtvtRegular;     sName: 'Noise';                                sVList: ''; sDesc: ''),
  672.     (iTag: $920e; VType: xtvtRegular;     sName: 'Focal Plane X-Resolution';             sVList: ''; sDesc: ''),
  673.     (iTag: $920f; VType: xtvtRegular;     sName: 'Focal Plane Y-Resolution';             sVList: ''; sDesc: ''),
  674.     (iTag: $9210; VType: xtvtRegular;     sName: 'Focal Plane Resolution Unit';
  675.       sVList: '1=None Specified:2=Inch:3=Centimeter';
  676.       sDesc: ''),
  677.     (iTag: $9211; VType: xtvtRegular;     sName: 'Image Number';                         sVList: ''; sDesc: ''),
  678.     (iTag: $9212; VType: xtvtRegular;     sName: 'Security Classification';              sVList: ''; sDesc: ''),
  679.     (iTag: $9213; VType: xtvtRegular;     sName: 'Image History';                        sVList: ''; sDesc: ''),
  680.     (iTag: $9214; VType: xtvtRegular;     sName: 'Subject Location';                     sVList: ''; sDesc: ''),
  681.     (iTag: $9215; VType: xtvtRegular;     sName: 'Exposure Index';                       sVList: ''; sDesc: ''),
  682.     (iTag: $9216; VType: xtvtRegular;     sName: 'TIFF/EPStandard ID';                   sVList: ''; sDesc: ''),
  683.     (iTag: $9217; VType: xtvtRegular;     sName: 'Sensing Method';                       sVList: ''; sDesc: ''),
  684.     (iTag: $923f; VType: xtvtRegular;     sName: 'StoNits';                              sVList: ''; sDesc: ''),
  685.     (iTag: $927c; VType: xtvtBinary;      sName: 'Maker Note';                           sVList: '';
  686.       sDesc: 'Maker-dependent internal data'),
  687.     (iTag: $9286; VType: xtvtUserComment; sName: 'User Comment';                         sVList: '';
  688.       sDesc:
  689.         'Comment tag. A tag used by EXIF users to write keywords or comments about the image besides those in '+
  690.         'Image Description and without the character-code limitations of the Image Description tag'),
  691.     (iTag: $9290; VType: xtvtRegular;     sName: 'Sub Sec Time';                         sVList: '';
  692.       sDesc:
  693.         'Some of digicam can take 2 to 30 pictures per second, but "Date & Time" tag cannot record the sub-second '+
  694.         'time. This tag is used to record it'),
  695.     (iTag: $9291; VType: xtvtRegular;     sName: 'Sub Sec Time Original';                sVList: '';
  696.       sDesc:
  697.         'Some of digicam can take 2 to 30 pictures per second, but "Original Date & Time" tag cannot record the '+
  698.         'sub-second time. This tag is used to record it'),
  699.     (iTag: $9292; VType: xtvtRegular;     sName: 'Sub Sec Time Digitized';               sVList: '';
  700.       sDesc:
  701.         'Some of digicam can take 2 to 30 pictures per second, but "Date & Time Digitized" tag cannot record the '+
  702.         'sub-second time. This tag is used to record it'),
  703.     (iTag: $953c; VType: xtvtRegular;     sName: 'Image Source Data';                    sVList: ''; sDesc: ''),
  704.     (iTag: $9c9b; VType: xtvtUnicode;     sName: 'Title';                                sVList: ''; sDesc: ''),
  705.     (iTag: $9c9c; VType: xtvtUnicode;     sName: 'Comments';                             sVList: ''; sDesc: ''),
  706.     (iTag: $9c9d; VType: xtvtUnicode;     sName: 'Author';                               sVList: ''; sDesc: ''),
  707.     (iTag: $9c9e; VType: xtvtUnicode;     sName: 'Keywords';                             sVList: ''; sDesc: ''),
  708.     (iTag: $9c9f; VType: xtvtUnicode;     sName: 'Subject';                              sVList: ''; sDesc: ''),
  709.     (iTag: $a000; VType: xtvtCharVersion; sName: 'FlashPix Version';                     sVList: '';
  710.       sDesc:
  711.         'FlashPix format version supported by an FPXR file. If the image data is based on FlashPix format Ver.1.0, '+
  712.         'value is "01.00"'),
  713.     (iTag: $a001; VType: xtvtRegular;     sName: 'Color Space';                          sVList: '0=sBW:1=sRGB:65535=Uncalibrated';
  714.       sDesc:
  715.         'Defines Color Space. DCF image must use sRGB color space. If the picture uses the other color space, value '+
  716.         'is Uncalibrated. Image data recorded as Uncalibrated can be treated as sRGB when it is converted to FlashPix'),
  717.     (iTag: $a002; VType: xtvtRegular;     sName: 'EXIF Image Width';                     sVList: '';
  718.       sDesc:
  719.         'Information specific to compressed data. When a compressed file is recorded, the valid width of the '+
  720.         'meaningful image must be recorded in this tag, whether or not there is padding data or a restart marker. '+
  721.         'This tag should not exist in an uncompressed file'),
  722.     (iTag: $a003; VType: xtvtRegular;     sName: 'EXIF Image Height';                    sVList: '';
  723.       sDesc:
  724.         'Information specific to compressed data. When a compressed file is recorded, the valid height of the '+
  725.         'meaningful image must be recorded in this tag whether or not there is padding data or a restart marker. '+
  726.         'This tag should not exist in an uncompressed file. Because data padding is unnecessary in the vertical '+
  727.         'direction, the number of lines recorded in this valid image height tag will be the same as that recorded in '+
  728.         'the SOF'),
  729.     (iTag: $a004; VType: xtvtRegular;     sName: 'Related Sound File';                   sVList: '';
  730.       sDesc:
  731.         'The name of an audio file related to the image data. The only relational information recorded is the EXIF '+
  732.         'audio file name and extension (an ASCII string that consists of 8 characters plus a period (.), plus 3 '+
  733.         'characters). The path is not recorded. When you use this tag, audio files must be recorded in conformance '+
  734.         'with the EXIF audio format. Writers can also store audio data within APP2 as FlashPix extension stream data'),
  735.     (iTag: $a005; VType: xtvtRegular;     sName: 'InteroperabilityIFD Offset';           sVList: '';
  736.       sDesc: 'Extension of "ExifR98", details are unknown. This value is offset to IFD format data'),
  737.     (iTag: $a20b; VType: xtvtRegular;     sName: 'Flash Energy';                         sVList: '';
  738.       sDesc: 'Strobe energy, in Beam Candle Power Seconds (BCPS), at the time the image was captured'),
  739.     (iTag: $a20c; VType: xtvtRegular;     sName: 'Spatial Frequency Response';           sVList: '';
  740.       sDesc:
  741.         'Camera or input device spatial frequency table and SFR values in the image width, image height, and '+
  742.         'diagonal direction, as specified in ISO 12233'),
  743.     (iTag: $a20e; VType: xtvtRegular;     sName: 'Focal Plane X-Resolution';             sVList: '';
  744.       sDesc:
  745.         'Pixel density at CCD''s position. If you have MegaPixel digicam and take a picture by lower resolution '+
  746.         '(e.g. VGA mode), this value is re-sampled by picture resolution. In such case, Focal Plane Resolution is '+
  747.         'not the same as CCD''s actual resolution'),
  748.     (iTag: $a20f; VType: xtvtRegular;     sName: 'Focal Plane Y-Resolution';             sVList: ''; 
  749.       sDesc:
  750.         'Pixel density at CCD''s position. If you have MegaPixel digicam and take a picture by lower resolution '+
  751.         '(e.g. VGA mode), this value is re-sampled by picture resolution. In such case, Focal Plane Resolution is '+
  752.         'not the same as CCD''s actual resolution'),
  753.     (iTag: $a210; VType: xtvtRegular;     sName: 'Focal Plane Resolution Unit';          sVList: '1=None Specified:2=Inch:3=Centimeter';
  754.       sDesc: 'Unit of Focal Plane X-Resoluton & Focal Plane Y-Resolution'),
  755.     (iTag: $a211; VType: xtvtRegular;     sName: 'Image Number';                         sVList: ''; sDesc: ''),
  756.     (iTag: $a212; VType: xtvtRegular;     sName: 'Security Classification';              sVList: ''; sDesc: ''),
  757.     (iTag: $a213; VType: xtvtRegular;     sName: 'Image History';                        sVList: '';
  758.       sDesc: 'Specifies the history of the image'),
  759.     (iTag: $a214; VType: xtvtRegular;     sName: 'Subject Location';                     sVList: '';
  760.       sDesc:
  761.         'Location of the main subject in the scene. The value of this tag represents the pixel at the center of the '+
  762.         'main subject relative to the left edge. The first value indicates the column number, and the second value '+
  763.         'indicates the row number'),
  764.     (iTag: $a215; VType: xtvtRegular;     sName: 'Exposure Index';                       sVList: '';
  765.       sDesc: 'Same as ISO Speed Ratings. Only Kodak''s digicams use this tag instead of ISO Speed Rating'),
  766.     (iTag: $a216; VType: xtvtRegular;     sName: 'TIFF/EPStandard ID';                   sVList: ''; sDesc: ''),
  767.     (iTag: $a217; VType: xtvtRegular;     sName: 'Sensing Method';
  768.       sVList:
  769.         '0=Unknown:1=Monochrome Area:2=One Chip Color Area:3=Two Chip Color Area:4=Three Chip Color Area:'+
  770.         '5=Color Sequential Area:6=Monochrome Linear:7=Trilinear:8=Color Sequential Linear';
  771.       sDesc: 'Shows type of image sensor unit'),
  772.     (iTag: $a300; VType: xtvtRegular;     sName: 'File Source';                          sVList: '1=Unknown:3=Digital Still Camera';
  773.       sDesc: 'Indicates the image source'),
  774.     (iTag: $a301; VType: xtvtRegular;     sName: 'Scene Type';                           sVList: '0=Unknown:1=Directly Photographed';
  775.       sDesc: 'Indicates the type of scene'),
  776.     (iTag: $a302; VType: xtvtRegular;     sName: 'CFA Pattern';                          sVList: '';
  777.       sDesc:
  778.         'Indicates the Color Filter Array (CFA) geometric pattern of the image sensor when a one-chip color area '+
  779.         'sensor is used. It does not apply to all sensing methods'),
  780.     (iTag: $a401; VType: xtvtRegular;     sName: 'Custom Rendered';                      sVList: '0=Normal process:1=Custom process'; sDesc: ''),
  781.     (iTag: $a402; VType: xtvtRegular;     sName: 'Exposure Mode';                        sVList: '0=Auto:1=Manual:2=Auto bracket'; sDesc: ''),
  782.     (iTag: $a403; VType: xtvtRegular;     sName: 'White Balance';                        sVList: '0=Auto:1=Manual'; sDesc: ''),
  783.     (iTag: $a404; VType: xtvtRegular;     sName: 'Digital Zoom Ratio';                   sVList: ''; sDesc: ''),
  784.     (iTag: $a405; VType: xtvtRegular;     sName: 'Focal Length In 35mm Film';            sVList: ''; sDesc: ''),
  785.     (iTag: $a406; VType: xtvtRegular;     sName: 'Scene Capture Type';
  786.       sVList: '0=Standard:1=Landscape:2=Portrait:3=Night scene';
  787.       sDesc: ''),
  788.     (iTag: $a407; VType: xtvtRegular;     sName: 'Gain Control';
  789.       sVList: '0=None:1=Low gain up:2=High gain up:3=Low gain down:4=High gain down';
  790.       sDesc: ''),
  791.     (iTag: $a408; VType: xtvtRegular;     sName: 'Contrast';                             sVList: '0=Normal:1=Soft:2=Hard'; sDesc: ''),
  792.     (iTag: $a409; VType: xtvtRegular;     sName: 'Saturation';                           sVList: '0=Normal:1=Low:2=High'; sDesc: ''),
  793.     (iTag: $a40a; VType: xtvtRegular;     sName: 'Sharpness';                            sVList: '0=Normal:1=Soft:2=Hard'; sDesc: ''),
  794.     (iTag: $a40b; VType: xtvtRegular;     sName: 'Device Setting Description';           sVList: ''; sDesc: ''),
  795.     (iTag: $a40c; VType: xtvtRegular;     sName: 'Subject Distance Range';
  796.       sVList: '0=Unknown:1=Macro:2=Close view:3=Distant view';
  797.       sDesc: ''),
  798.     (iTag: $a420; VType: xtvtRegular;     sName: 'Image Unique ID';                      sVList: '0=Close view:1=Distant view'; sDesc: ''));
  799.  
  800.    // Returns pointer to EXIF tag entry, nil if not found
  801.   function FindEXIFTag(iTag: Integer): PEXIFTag;
  802.  
  803. implementation
  804. uses phUtils;
  805.  
  806.    // Intel-to-Motorola (and back) byte-order data conversion
  807.  
  808.   function IMTranslateWord(w: Word): Word;
  809.   begin
  810.     Result := (w shl 8) or (w shr 8);
  811.   end;
  812.  
  813.   function IMTranslateInt(i: Integer): Integer;
  814.   begin
  815.     Result := (i shl 24) or (i shl 8 and $00ff0000) or (i shr 8 and $0000ff00) or (i shr 24);
  816.   end;
  817.  
  818.   function IMTranslateRational(i64: Int64): Int64;
  819.   begin
  820.     Result := Int64(IMTranslateInt(i64 shr 32)) shl 32 or IMTranslateInt(i64);
  821.   end;
  822.  
  823.    // Misc routines
  824.  
  825.   function FindEXIFTag(iTag: Integer): PEXIFTag;
  826.   var i: Integer;
  827.   begin
  828.     for i := 0 to High(aEXIFTags) do begin
  829.       Result := @aEXIFTags[i];
  830.       if Result^.iTag=iTag then Exit;
  831.     end;
  832.     Result := nil;
  833.   end;
  834.   
  835.    //===================================================================================================================
  836.    // TImageMetadata
  837.    //===================================================================================================================
  838.  
  839.   constructor TImageMetadata.Create(const sFileName: String);
  840.   var fs: TFileStream;
  841.   begin
  842.     inherited Create;
  843.     FStatusCode := IMS_Unknown;
  844.     FEXIFData := TStringList.Create;
  845.      // Create a file stream to load data from
  846.     try
  847.       fs := TFileStream.Create(sFileName, fmOpenRead or fmShareDenyWrite);
  848.     except
  849.        // Handle any exception translating it into the appropriate StatusCode
  850.       SetStatusCode(IMS_CannotOpenFile);
  851.       fs := nil; // Satisfy the compiler
  852.     end;
  853.      // If file is open successfully
  854.     if not FFailed then
  855.       try
  856.         LoadFromStream(fs);
  857.       finally
  858.         fs.Free;
  859.       end;
  860.   end;
  861.  
  862.   destructor TImageMetadata.Destroy;
  863.   begin
  864.     FEXIFData.Free;
  865.     inherited Destroy;
  866.   end;
  867.  
  868.   function TImageMetadata.FetchMarkerData(Stream: TStream; bSkip: Boolean): String;
  869.   var wSize: Word;
  870.   begin
  871.     Result := '';
  872.      // Data size includes size-bytes' length itself
  873.     if not FFailed then begin
  874.       wSize := FetchWord(Stream, True)-2;
  875.       try
  876.         if bSkip then
  877.           Stream.Seek(wSize, soCurrent)
  878.         else begin
  879.           SetLength(Result, wSize);
  880.           Stream.ReadBuffer(Result[1], wSize);
  881.         end;
  882.       except
  883.         SetStatusCode(IMS_ReadFailure);
  884.       end;
  885.     end;
  886.   end;
  887.  
  888.   function TImageMetadata.FetchWord(Stream: TStream; bMotorola: Boolean): Word;
  889.   begin
  890.     try
  891.       Stream.ReadBuffer(Result, SizeOf(Result));
  892.     except
  893.       SetStatusCode(IMS_ReadFailure);
  894.     end;
  895.     if not FFailed and bMotorola then Result := IMTranslateWord(Result);
  896.   end;
  897.  
  898.   procedure TImageMetadata.LoadFromStream(Stream: TStream);
  899.   var wMarker: Word;
  900.   begin
  901.      // Parse markers consequently
  902.     Stream.Seek(0, soBeginning);
  903.     while not FFailed do begin
  904.       wMarker := FetchWord(Stream, True);
  905.       if not FFailed then begin
  906.          // A JPEG file *must* start with SOI marker
  907.         if not FDataFetched then begin
  908.           if wMarker<>JM_SOI then SetStatusCode(IMS_NotAJPEGFile);
  909.          // Not a first marker, go on
  910.         end else
  911.           case wMarker of
  912.              // EOI or SOS encountered, get out
  913.             JM_EOI, JM_SOS: Break;
  914.              // EXIF data to be parsed out
  915.             JM_EXIF: begin
  916.               ParseEXIFMarkerData(FetchMarkerData(Stream, False));
  917.               Exit;
  918.             end;
  919.              // All other tags are skipped
  920.             else FetchMarkerData(Stream, True);
  921.           end;
  922.         FDataFetched := True;
  923.       end;
  924.     end;
  925.      // If no metadata found
  926.     if not FFailed then SetStatusCode(IMS_NoMetadata);
  927.   end;
  928.  
  929.   procedure TImageMetadata.ParseEXIFMarkerData(const sData: String);
  930.   var
  931.     sTIFFHeader, sRaw: String;
  932.     bMotorolaOrder: Boolean;
  933.     iIFDOffset: Integer;
  934.   begin
  935.      // Check EXIF header
  936.     if (Length(sData)<6+8) or (Copy(sData, 1, 6)<>SEXIFHeader) then
  937.       SetStatusCode(IMS_InvalidEXIFHeader)
  938.     else begin
  939.        // Check TIFF header / Get TIFF byte order
  940.       sTIFFHeader := Copy(sData, 7, 4);
  941.       if sTIFFHeader=STIFFIntelHeader then
  942.         bMotorolaOrder := False
  943.       else if sTIFFHeader=STIFFMotorolaHeader then
  944.         bMotorolaOrder := True
  945.       else begin
  946.         SetStatusCode(IMS_InvalidTIFFHeader);
  947.         Exit;
  948.       end;
  949.        // Get IFD Offset
  950.       Move(sData[11], iIFDOffset, 4);
  951.       if bMotorolaOrder then iIFDOffset := IMTranslateInt(iIFDOffset);
  952.        // Process chained IFDs. Offset is computed relative to the TIFF header
  953.       sRaw := Copy(sData, 7, MaxInt);
  954.       while iIFDOffset<>0 do iIFDOffset := ProcessIFD(sRaw, iIFDOffset, bMotorolaOrder);
  955.        // Set status to indicate success
  956.       if not FFailed then SetStatusCode(IMS_OK);
  957.     end;
  958.   end;
  959.  
  960.   function TImageMetadata.ProcessIFD(const sData: String; iOffset: Integer; bMotorola: Boolean): Integer;
  961.   var
  962.     iDataLen, iEntDataSize, iComponentSize, i: Integer;
  963.     wEntCount, wEntry: Word;
  964.     IE: TIFDEntry;
  965.     pt: PEXIFTag;
  966.     sCompValue, sTagValue: String;
  967.     i64Component: Int64;
  968.  
  969.      // Retrieves data component at specified Index (0..iCompCount-1). Returns True if retrieval succeeded
  970.     function GetComponent(iIndex: Integer; out i64CompValue: Int64): Boolean;
  971.     var ptr: Pointer;
  972.     begin
  973.       i64CompValue := 0;
  974.        // Value smaller than or equal to 4 bytes size is stored directly in IE.iData
  975.       if iEntDataSize<=4 then
  976.         ptr := @IE.iData
  977.        // For longer data iData is the offset. Check data size 
  978.       else if IE.iData+iComponentSize>iDataLen then begin
  979.         Result := False;
  980.         Exit;
  981.       end else
  982.         ptr := @sData[IE.iData+1];
  983.        // Move pointer to specified index
  984.       Inc(Integer(ptr), iComponentSize*iIndex);
  985.        // Get data, convert from Motorola byte-order if required (only data retrieved through offset)
  986.       Move(ptr^, i64CompValue, iComponentSize);
  987.       if bMotorola and (iEntDataSize>4) then
  988.         case IE.wFmt of
  989.           {2} iedUShort, iedSShort:       i64CompValue := IMTranslateWord(Word(i64CompValue));
  990.           {4} iedULong, iedSLong:         i64CompValue := IMTranslateInt(Integer(i64CompValue));
  991.           {8} iedURational, iedSRational: i64CompValue := IMTranslateRational(i64CompValue);
  992.         end;
  993.       Result := True;
  994.     end;
  995.  
  996.      // Translates numeric Value to string
  997.     function GetComponentAsString(i64Value: Int64): String;
  998.     var
  999.       sValue: Single absolute i64Value;
  1000.       dValue: Double absolute i64Value;
  1001.     begin
  1002.       case IE.wFmt of
  1003.         iedUByte, iedUndef: Result := IntToStr(Byte(i64Value));
  1004.         iedAscii:           Result := iif(i64Value and $ff=0, '', Char(i64Value)); // Skip terminating char (#0)
  1005.         iedUShort:          Result := IntToStr(Word(i64Value));
  1006.         iedULong:           Result := IntToStr(Cardinal(i64Value));
  1007.         iedURational:       Result := Format('%d/%d', [Cardinal(i64Value shr 32), Cardinal(i64Value)]);
  1008.         iedSByte:           Result := IntToStr(ShortInt(i64Value));
  1009.         iedSShort:          Result := IntToStr(SmallInt(i64Value));
  1010.         iedSLong:           Result := IntToStr(Integer(i64Value));
  1011.         iedSRational:       Result := Format('%d/%d', [Integer(i64Value shr 32), Integer(i64Value)]);
  1012.         iedSingleFloat:     Result := FloatToStr(sValue);
  1013.         iedDoubleFloat:     Result := FloatToStr(dValue);
  1014.       end;
  1015.     end;
  1016.  
  1017.      // Decodes component value according to decoding list
  1018.     function DecodeComponentValue(const sValue: String): String;
  1019.     var s, sExpr: String;
  1020.     begin
  1021.       s := pt^.sVList;
  1022.       repeat
  1023.         sExpr := ExtractFirstWord(s, ':');
  1024.         if sValue=ExtractFirstWord(sExpr, '=') then begin
  1025.           Result := sExpr;
  1026.           Exit;
  1027.         end;
  1028.       until s='';
  1029.       Result := sValue;
  1030.     end;
  1031.  
  1032.      // Translates a buffer string containing Unicode characters to Ansi using the current system charset
  1033.     function UnicodeBufToAnsi(const sBuffer: String): String;
  1034.     var
  1035.       ws: WideString;
  1036.       iLen: Integer;
  1037.     begin
  1038.       iLen := Length(sBuffer) div 2;
  1039.        // Move wide chars to ws
  1040.       SetLength(ws, iLen);
  1041.       Move(sBuffer[1], ws[1], iLen*2);
  1042.        // Translate wide chars to Ansi chars
  1043.       SetLength(Result, iLen);
  1044.       WideCharToMultiByte(CP_ACP, 0, @ws[1], iLen, @Result[1], iLen, nil, nil);
  1045.        // Trim control chars & null-terminator
  1046.       Result := Trim(Result); 
  1047.     end;
  1048.  
  1049.      // Processes data of xtvtUserComment format
  1050.     function FormatUserComment(const sBuffer: String): String;
  1051.     var sCode, sValue: String;
  1052.     begin
  1053.        // The first 8 bytes indicate charset. The rest are value
  1054.       sCode  := Copy(sTagValue, 1, 7);
  1055.       sValue := Copy(sTagValue, 9, MaxInt);
  1056.        // Make the only distinction for Unicode here
  1057.       if AnsiSameText(sCode, 'UNICODE') then Result := UnicodeBufToAnsi(sValue) else Result := Trim(sValue);
  1058.     end;
  1059.  
  1060.      // Formats raw binary data as hexadecimal ASCII representation (without any delimiters)
  1061.     function FormatRawBinary(const sBuffer: String): String;
  1062.     const acHexChars: Array[$0..$f] of Char = '0123456789abcdef';
  1063.     var
  1064.       i: Integer;
  1065.       b: Byte;
  1066.     begin
  1067.       i := Length(sBuffer);
  1068.       SetLength(Result, i*2);
  1069.       for i := 1 to i do begin
  1070.         b := Byte(sBuffer[i]);
  1071.         Result[i*2-1] := acHexChars[b div 16];
  1072.         Result[i*2]   := acHexChars[b mod 16];
  1073.       end;
  1074.     end;
  1075.  
  1076.   begin
  1077.     Result := 0;
  1078.     iDataLen := Length(sData);
  1079.      // Get entries count. If offset points outside the data, just skip this IFD
  1080.     if iDataLen-iOffset<2 then Exit;
  1081.     Move(sData[iOffset+1], wEntCount, 2);
  1082.     if bMotorola then wEntCount := IMTranslateWord(wEntCount);
  1083.      // Check data size. If offset points outside the data, just skip this IFD
  1084.     if iDataLen-iOffset<2+wEntCount*12+4 then Exit;
  1085.      // Iterate thru IFD's entries
  1086.     Inc(iOffset, 2);
  1087.     for wEntry := 0 to wEntCount-1 do begin
  1088.       Move(sData[iOffset+1], IE, SizeOf(IE));
  1089.        // Convert from Motorola byte-order if necessary
  1090.       if bMotorola then
  1091.         with IE do begin
  1092.           wTag     := IMTranslateWord(wTag);
  1093.           wFmt     := IMTranslateWord(wFmt);
  1094.           iCompCnt := IMTranslateInt(iCompCnt);
  1095.           iData    := IMTranslateInt(iData);
  1096.         end;
  1097.        // Try to find tag
  1098.       pt := FindEXIFTag(IE.wTag);
  1099.        // Check tag, component count and datatype
  1100.       if (pt<>nil) and (IE.iCompCnt>0) and (IE.wFmt>=1) and (IE.wFmt<=12) then begin
  1101.          // Compute data size
  1102.         iComponentSize := aIFDEntSize[IE.wFmt];
  1103.         iEntDataSize := IE.iCompCnt*iComponentSize;
  1104.          // Compose tag value
  1105.         sTagValue := '';
  1106.         for i := 0 to IE.iCompCnt-1 do begin
  1107.           if not GetComponent(i, i64Component) then begin
  1108.             sTagValue := '(error)';
  1109.             Break;
  1110.           end;
  1111.           case pt^.VType of
  1112.              // Regular value: translate it on-the-fly
  1113.             xtvtRegular: begin
  1114.               sCompValue := GetComponentAsString(i64Component);
  1115.                // If component is to be decoded
  1116.               if pt^.sVList<>'' then begin
  1117.                 sTagValue := DecodeComponentValue(sCompValue);
  1118.                 Break;
  1119.               end;
  1120.                // ASCII strings are simply concatenated, other data values are separated with comma
  1121.               if IE.wFmt=iedAscii then sTagValue := sTagValue+sCompValue else AccumulateStr(sTagValue, ',', sCompValue);
  1122.                // If the component is an IFD offset, then process this IFD
  1123.               if (IE.wTag=EXIF_TAG_SUBIFD) or (IE.wTag=EXIF_TAG_INTEROPIFD) then ProcessIFD(sData, i64Component, bMotorola);
  1124.             end;
  1125.              // Other values - to be processed later, accumulate them as binary string
  1126.             else sTagValue := sTagValue+Char(i64Component);
  1127.           end;
  1128.         end;
  1129.          // Post-process the non-regular value
  1130.         case pt^.VType of
  1131.           xtvtUserComment: sTagValue := FormatUserComment(sTagValue);
  1132.           xtvtCharVersion: sTagValue := Copy(sTagValue, 1, 2)+'.'+Copy(sTagValue, 3, MaxInt);
  1133.           xtvtUnicode:     sTagValue := UnicodeBufToAnsi(sTagValue);
  1134.           xtvtBinary:      sTagValue := FormatRawBinary(sTagValue);
  1135.         end;
  1136.          // Register value
  1137.         FEXIFData.AddObject(sTagValue, Pointer(IE.wTag));
  1138.       end;
  1139.       Inc(iOffset, 12);
  1140.     end;
  1141.      // The last four bytes are always offset to the next IFD, or zero if no one
  1142.     Move(sData[iOffset+1], Result, SizeOf(Result));
  1143.     if bMotorola then Result := IMTranslateInt(Result);
  1144.   end;
  1145.  
  1146.   procedure TImageMetadata.SetStatusCode(iCode: Integer);
  1147.   begin
  1148.     FStatusCode := iCode;
  1149.     if iCode<>IMS_OK then FFailed := True; 
  1150.   end;
  1151.  
  1152. end.
  1153.